package com.uduemc.biso.node.web.api.service.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.ZipUtil;
import com.uduemc.biso.core.extities.center.Host;
import com.uduemc.biso.core.utils.RestResult;
import com.uduemc.biso.node.core.common.feign.CHostBackupRestoreFeign;
import com.uduemc.biso.node.core.entities.HBackup;
import com.uduemc.biso.node.core.property.GlobalProperties;
import com.uduemc.biso.node.core.utils.RestResultUtil;
import com.uduemc.biso.node.core.utils.SitePathUtil;
import com.uduemc.biso.node.web.api.service.BackupRestoreService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;

@Service
@Slf4j
public class BackupRestoreServiceImpl implements BackupRestoreService {

    @Resource
    private GlobalProperties globalProperties;

    @Resource
    private CHostBackupRestoreFeign cHostBackupRestoreFeign;

    @Override
    public File backupRun(Host host, HBackup hBackup) {
        if (hBackup == null) {
            log.error("hostId:" + host.getId() + " 执行备份操作，HBackup 数据为空！");
            return null;
        }

        // 创建临时备份的目录
        String basePath = globalProperties.getSite().getBasePath();
        String tmpDirectory = "";
        try {
            tmpDirectory = makeTMPDirectory(host, basePath, hBackup.getId());
        } catch (IOException e) {
            log.error("hostId:" + host.getId() + " 执行备份操作失败，" + e.getMessage());
            return null;
        }
        if (StrUtil.isBlank(tmpDirectory)) {
            log.error("hostId:" + host.getId() + " 执行备份操作，生成的临时备份目录为空！");
            return null;
        }

        if (FileUtil.isDirectory(tmpDirectory) || FileUtil.isFile(tmpDirectory)) {
            FileUtil.del(tmpDirectory);
        }
        if (FileUtil.mkdir(tmpDirectory) == null) {
            log.error("hostId:" + host.getId() + " 执行备份操作，系统创建 " + tmpDirectory + " 目录失败！");
            return null;
        }

        String userBackupPath = SitePathUtil.getUserBackupPathByCode(basePath, host.getRandomCode());
        if (!FileUtil.isDirectory(userBackupPath)) {
            if (FileUtil.mkdir(userBackupPath) == null) {
                log.error("hostId:" + host.getId() + " 执行备份操作，系统创建 " + userBackupPath + " 目录失败！");
                return null;
            }
        }

        // 定义备份各个数据文件位置
        // 数据目录
        String tmpDataDirectory = tmpDirectory + File.separator + "data";
        // 文件目录
        String tmpFileDirectory = tmpDirectory + File.separator + "file";
        if (FileUtil.mkdir(tmpDataDirectory) == null) {
            log.error("hostId:" + host.getId() + " 执行备份操作，系统创建 " + tmpDataDirectory + " 目录失败！");
            return null;
        }
        if (FileUtil.mkdir(tmpFileDirectory) == null) {
            log.error("hostId:" + host.getId() + " 执行备份操作，系统创建 " + tmpFileDirectory + " 目录失败！");
            return null;
        }

        // 数据备份
        RestResult restResult = cHostBackupRestoreFeign.backup(host.getId(), tmpDataDirectory);
        try {
            String cHostBackupRestoreBackup = RestResultUtil.data(restResult, String.class);
            if (!cHostBackupRestoreBackup.equals(tmpDataDirectory)) {
                log.error("hostId:" + host.getId() + " 执行备份操作，数据备份结果的目录地址不匹配，cHostBackupRestoreBackup:" + cHostBackupRestoreBackup + "， tmpDataDirectory:"
                        + tmpDataDirectory);
                return null;
            }
        } catch (IOException e) {
            log.error("hostId:" + host.getId() + " 执行备份数据操作失败，" + e.getMessage());
            return null;
        }

        // 文件备份
        // 复制资源文件
        String userRepertoryPath = SitePathUtil.getUserRepertoryPathByCode(basePath, host.getRandomCode());
        if (FileUtil.isDirectory(userRepertoryPath)) {
            FileUtil.copy(userRepertoryPath, tmpFileDirectory, true);
        }
        // 复制虚拟目录文件
        String userVirtualFolderPath = SitePathUtil.getUserVirtualFolderPathByCode(basePath, host.getRandomCode());
        if (FileUtil.isDirectory(userVirtualFolderPath)) {
            FileUtil.copy(userVirtualFolderPath, tmpFileDirectory, true);
        }
        // 复制网站图标 icon 文件
        String userFaviconIcoPath = SitePathUtil.getUserFaviconIcoPathByCode(basePath, host.getRandomCode());
        if (FileUtil.isFile(userFaviconIcoPath)) {
            FileUtil.copy(userFaviconIcoPath, tmpFileDirectory, true);
        }
        // 复制网站 Watermark 文件夹
        String userWatermarkPath = SitePathUtil.getUserWatermarkPathByCode(basePath, host.getRandomCode());
        if (FileUtil.isDirectory(userWatermarkPath)) {
            FileUtil.copy(userWatermarkPath, tmpFileDirectory, true);
        }
        // 复制网站 Template 文件夹
        String userTemplatePath = SitePathUtil.getUserTemplatePathByCode(basePath, host.getRandomCode());
        if (FileUtil.isDirectory(userTemplatePath)) {
            FileUtil.copy(userTemplatePath, tmpFileDirectory, true);
        }

        // 压缩
        File backupZip = ZipUtil.zip(tmpDirectory);
        if (!backupZip.isFile()) {
            log.error("hostId:" + host.getId() + " 执行备份操作失败，对目录 zip 压缩失败！tmpDirectory:" + tmpDirectory);
            return null;
        }

        // 移动压缩文件至备份目录
        String zip = userBackupPath + File.separator + FileUtil.getName(backupZip);
        File zipFile = new File(zip);
        FileUtil.move(backupZip, zipFile, true);
        FileUtil.del(tmpDirectory);

        // 返回验证的结果
        if (FileUtil.isFile(zipFile)) {
            return zipFile;
        }
        return null;
    }

    @Override
    public boolean restoreRun(Host host, HBackup hBackup) {
        if (hBackup == null) {
            log.error("hostId:" + host.getId() + " 执行还原操作，HBackup 数据为空！");
            return false;
        }

        // 创建临时备份的目录
        String basePath = globalProperties.getSite().getBasePath();
        String tmpDirectory = "";
        try {
            tmpDirectory = makeTMPDirectory(host, basePath, hBackup.getId());
        } catch (IOException e) {
            log.error("hostId:" + host.getId() + " 执行还原操作失败，" + e.getMessage());
            return false;
        }
        if (StrUtil.isBlank(tmpDirectory)) {
            log.error("hostId:" + host.getId() + " 执行还原操作，生成的临时备份目录为空！");
            return false;
        }

        if (FileUtil.isDirectory(tmpDirectory) || FileUtil.isFile(tmpDirectory)) {
            FileUtil.del(tmpDirectory);
        }
        if (FileUtil.mkdir(tmpDirectory) == null) {
            log.error("hostId:" + host.getId() + " 执行还原操作，系统创建 " + tmpDirectory + " 目录失败！");
            return false;
        }

        String absoluteHBackupZipPath = SitePathUtil.getUserHBackupZipPath(host, basePath, hBackup);
        if (StrUtil.isBlank(absoluteHBackupZipPath) || !FileUtil.isFile(absoluteHBackupZipPath)) {
            log.error("hostId:" + host.getId() + " 执行还原操作，获取的备份文件的绝对路径不存在文件！absoluteHBackupZipPath:" + absoluteHBackupZipPath);
            return false;
        }
        File hBackupZipFile = new File(absoluteHBackupZipPath);

        // 解压备份文件至 创建的临时目录下
        ZipUtil.unzip(hBackupZipFile, new File(tmpDirectory));

        // 数据目录
        String tmpDataDirectory = tmpDirectory + File.separator + "data";
        // 文件目录
        String tmpFileDirectory = tmpDirectory + File.separator + "file";

        if (!FileUtil.isDirectory(tmpDataDirectory) || !FileUtil.isDirectory(tmpFileDirectory)) {
            log.error("hostId:" + host.getId() + " 执行还原操作，解压备份文件后的目录有误，absoluteHBackupZipPath:" + absoluteHBackupZipPath);
            return false;
        }

        // 数据还原
        RestResult restResult = cHostBackupRestoreFeign.restore(host.getId(), tmpDataDirectory);
        try {
            String cHostBackupRestoreRestore = RestResultUtil.data(restResult, String.class);
            if (!cHostBackupRestoreRestore.equals(tmpDataDirectory)) {
                log.error("hostId:" + host.getId() + " 执行还原操作，数据还原结果的目录地址不匹配，cHostBackupRestoreRestore:" + cHostBackupRestoreRestore + "， tmpDataDirectory:"
                        + tmpDataDirectory);
                return false;
            }
        } catch (IOException e) {
            log.error("hostId:" + host.getId() + " 执行还原数据操作失败，" + e.getMessage());
            return false;
        }

        // 文件还原
        // 创建临时保存当前客户文件的目录
        String tmpCurrentBackupFileDirectory = tmpDirectory + File.separator + "current";
        if (FileUtil.mkdir(tmpCurrentBackupFileDirectory) == null) {
            log.error("hostId:" + host.getId() + " 执行还原操作，系统创建 " + tmpCurrentBackupFileDirectory + " 目录失败！");
            return false;
        }

        // 备份客户当前目录下文件
        String userRepertoryPath = SitePathUtil.getUserRepertoryPathByCode(basePath, host.getRandomCode());
        if (FileUtil.isDirectory(userRepertoryPath)) {
            FileUtil.move(new File(userRepertoryPath), new File(tmpCurrentBackupFileDirectory), true);
        }
        // 复制虚拟目录文件
        String userVirtualFolderPath = SitePathUtil.getUserVirtualFolderPathByCode(basePath, host.getRandomCode());
        if (FileUtil.isDirectory(userVirtualFolderPath)) {
            FileUtil.move(new File(userVirtualFolderPath), new File(tmpCurrentBackupFileDirectory), true);
        }
        // 复制网站图标 icon 文件
        String userFaviconIcoPath = SitePathUtil.getUserFaviconIcoPathByCode(basePath, host.getRandomCode());
        if (FileUtil.isFile(userFaviconIcoPath)) {
            FileUtil.move(new File(userFaviconIcoPath), new File(tmpCurrentBackupFileDirectory), true);
        }
        // 复制网站 Watermark 文件夹
        String userWatermarkPath = SitePathUtil.getUserWatermarkPathByCode(basePath, host.getRandomCode());
        if (FileUtil.isDirectory(userWatermarkPath)) {
            FileUtil.move(new File(userWatermarkPath), new File(tmpCurrentBackupFileDirectory), true);
        }
        // 复制网站 Template 文件夹
        String userTemplatePath = SitePathUtil.getUserTemplatePathByCode(basePath, host.getRandomCode());
        if (FileUtil.isDirectory(userTemplatePath)) {
            FileUtil.move(new File(userTemplatePath), new File(tmpCurrentBackupFileDirectory), true);
        }

        // 用户根目录
        String userPathByCode = SitePathUtil.getUserPathByCode(basePath, host.getRandomCode());

        // 还原文件动作，如果失败则需要还原客户当前目录下文件
        File[] ls = FileUtil.ls(tmpFileDirectory);
        log.info("tmpFileDirectory:" + tmpFileDirectory + " -> " + Arrays.asList(ls));
        for (File file : ls) {
            String name = file.getName();
            if (!name.equals(".") && !name.equals("..")) {
                File copy = FileUtil.copy(file, new File(userPathByCode), true);
                if (copy == null) {
                    log.error("hostId:" + host.getId() + " 执行还原操作，文件还原操作失败，复制备份文件 " + file + "，到用户更目录下！userPathByCode:" + userPathByCode);
                    // 还原之前的操作
                    FileUtil.del(userRepertoryPath);
                    FileUtil.del(userVirtualFolderPath);
                    FileUtil.del(userFaviconIcoPath);
                    FileUtil.del(userWatermarkPath);
                    FileUtil.del(userTemplatePath);

                    File[] tmpls = FileUtil.ls(tmpCurrentBackupFileDirectory);
                    for (File tmplsfile : tmpls) {
                        String tmplsname = tmplsfile.getName();
                        if (!tmplsname.equals(".") && !tmplsname.equals("..")) {
                            FileUtil.move(tmplsfile, new File(userPathByCode), true);
                        }
                    }
                    return false;
                }
            }
        }

        // 最后删除还原客户备份的临时解压目录
        return FileUtil.del(tmpDirectory);
    }

    public static String makeTMPDirectory(Host host, String basePath, long hBackupId) throws IOException {
        String tmpPath = SitePathUtil.getUserTMPPathByCodeAndHBackupId(basePath, host.getRandomCode(), hBackupId);
        return new File(tmpPath).getCanonicalPath();
    }

    public static String makeBackupDirectory(Host host, String basePath, HBackup hBackup) throws IOException {
        String tmpPath = SitePathUtil.getUserPathByCode(basePath, host.getRandomCode()) + File.separator + hBackup.getFilepath();
        return new File(tmpPath).getCanonicalPath();
    }

}
